<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Clone Test-Suite (Browser)</title>
    <script>
      var module = {};
      var tests = exports = module.exports = {};

      function require(moduleName) {
        if (moduleName == './') {
          return clone;
        }
      }

      function log(str) {
        logList.innerHTML += '<li>' + str + '</li>';
      }
    </script>
    <script src="clone.js"></script>
    <script src="test.js"></script>
  </head>
  <body>
    <h1 id="nodeunit-header">Clone Test-Suite (Browser)</h1>
    Tests started: <span id="testsStarted"></span>;
    Tests finished: <span id="testsFinished"></span>.
    <ul id="logList"></ul>
    <script>
      /* Methods copied from
       * https://github.com/caolan/nodeunit/blob/master/lib/assert.js
       */
      function isUndefinedOrNull(value) {
        return value === null || value === undefined;
      }

      function isArguments(object) {
        return Object.prototype.toString.call(object) == '[object Arguments]';
      }

      var _keys = function (obj){
        if (Object.keys) return Object.keys(obj);
        if (typeof obj != 'object' && typeof obj != 'function') {
          throw new TypeError('-');
        }
        var keys = [];
        for(var k in obj) if(obj.hasOwnProperty(k)) keys.push(k);
        return keys;
      };

      function objEquiv(a, b) {
        if (isUndefinedOrNull(a) || isUndefinedOrNull(b))
          return false;

        if (a.prototype !== b.prototype)
          return false;

        if (isArguments(a)) {
          if (!isArguments(b)) return false;
          a = pSlice.call(a);
          b = pSlice.call(b);
          return _deepEqual(a, b);
        }

        try {
          var ka = _keys(a), kb = _keys(b), key, i;
        } catch (e) {
          return false
        }

        if (ka.length != kb.length)
          return false;

        ka.sort();
        kb.sort();

        for (i = ka.length - 1; i >= 0; i--) {
          if (ka[i] != kb[i]) return false;
        }

        for (i = ka.length - 1; i >= 0; i--) {
          key = ka[i];
          if (!_deepEqual(a[key], b[key] ))
            return false;
        }

        return true;
      }
      function _deepEqual(actual, expected) {
        if (actual === expected) {
          return true;
        } else if (actual instanceof Date && expected instanceof Date) {
          return actual.getTime() === expected.getTime();
        } else if (actual instanceof RegExp && expected instanceof RegExp) {
          return actual.source === expected.source &&
              actual.global === expected.global &&
              actual.ignoreCase === expected.ignoreCase &&
              actual.multiline === expected.multiline;
        } else if (typeof actual != 'object' && typeof expected != 'object') {
          return actual == expected;
        } else {
          return objEquiv(actual, expected);
        }
      }

      for (var testName in tests) {
        setTimeout((function (testName) {
          try {
            testsStarted.innerHTML = (parseInt(testsStarted.innerHTML) || 0) + 1;
            function incFinished() {
              testsFinished.innerHTML = (parseInt(testsFinished.innerHTML) || 0) + 1;
            }

            tests[testName]({
              expect: function (num) {
                this._expect = num
              },
              ok: function (val) {
                if(!val) throw new Error(val + ' is not ok.')
              },
              equal: function (a,b) {
                if (a != b) throw new Error(a + ' is not equal to ' + b)
              },
              notEqual: function (a,b) {
                if (a == b) throw new Error(a + ' is equal to ' + b)
              },
              strictEqual: function (a,b) {
                if (a !== b) throw new Error(a + ' is not strict equal to ' + b)
              },
              deepEqual: function (a,b) {
                if (!_deepEqual(a,b))
                  throw new Error(JSON.stringify(a) + ' is not deep equal to ' +
                                  JSON.stringify(b))
              },
              done: function () {
                log(testName + ' <span style="color:blue">is ok</span>.');
                incFinished();
              }
            });
          } catch(e) {
            log(testName + ' <span style="color:red">FAIL.</span> <small>'+ e +'</small>');
            incFinished();
            console.log(e);
          }
        })(testName), 1);
      }
    </script>
  </body>
</html>
